﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Configuration;

namespace MarketSimulator.Utils.Market
{
    public static class ProductCreator
    {
        #region Private Members

        private const string PRODUCT_NODE = "product";
        private const string PRODUCT_NAME = "name";
        private const string PRODUCT_UNIT_STORAGE_CAPACITY = "requiredUnitStorageCapacity";
        private const string PRODUCT_UNIT_COST_LOW = "priceunitCostLow";
        private const string PRODUCT_UNIT_COST_HIGH = "unitCostHigh";

        private static object productListLock = new object();

        #endregion

        #region Properties

        /// <summary>
        /// Product Types
        /// </summary>
        public static IList<ProductType> ProductTypes { get; set; }

        /// <summary>
        /// Product File Description
        /// </summary>
        public static string ProductDescriptionFile
        {
            get
            {
                return ConfigurationManager.AppSettings["productsXML"];
            }
        }

        #endregion

        #region Public Methods

        public static void ReadProductTypes()
        {
            ProductTypes = new List<ProductType>();
            XmlTextReader reader = new XmlTextReader(ProductDescriptionFile);
            ProductType currentProductType = null;
            string lastElementName = string.Empty;

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element && reader.LocalName.Equals(PRODUCT_NODE))
                {
                    string name = reader.GetAttribute(PRODUCT_NAME);
                    double priceHigh = 0;
                    double priceLow = 0;
                    long storageCapacityRequired = 0;

                    double.TryParse(reader.GetAttribute(PRODUCT_UNIT_COST_HIGH), out priceHigh);
                    double.TryParse(reader.GetAttribute(PRODUCT_UNIT_COST_LOW), out priceLow);
                    long.TryParse(reader.GetAttribute(PRODUCT_UNIT_STORAGE_CAPACITY), out storageCapacityRequired);

                    currentProductType = new ProductType()
                    {
                        Name = name,
                        UnitCostHigh = priceHigh,
                        UnitCostLow = priceLow,
                        RequiredUnitStorageCapacity = storageCapacityRequired
                    };

                    //The tag is closed
                    if (reader.IsEmptyElement)
                    {
                        ProductTypes.Add(currentProductType);
                        currentProductType = null;
                    }
                }
                else if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName.Equals("product") && currentProductType != null)
                {
                    ProductTypes.Add(currentProductType);
                    currentProductType = null;
                }
            }
        }

        /// <summary>
        /// Creates a new Product from a ProductType
        /// </summary>
        /// <param name="productType"></param>
        /// <returns></returns>
        private static Product CreateProductFromType(ProductType productType)
        {
            Random rand = new Random(DateTime.Now.Millisecond);
            Product newProduct = new Product()
            {
                Name = productType.Name,
                Quantity = rand.Next(1, 100),
                UnitCost = rand.Next((int)Math.Ceiling(productType.UnitCostLow), (int)Math.Floor(productType.UnitCostHigh))
            };
            return newProduct;
        }

        /// <summary>
        /// Create list of products for the Seller
        /// </summary>
        /// <returns>List of Products</returns>
        public static IList<Product> CreateProductList()
        {
            lock (productListLock)
            {
                //Random number generator
                Random rand = new Random(DateTime.Now.Millisecond);
                int maxValue = ProductTypes.Count;
                int itemsToSelect = rand.Next(1, maxValue);
                IList<Product> newProductsList = new List<Product>(itemsToSelect);

                if (itemsToSelect == ProductTypes.Count)
                {
                    foreach (var productType in ProductTypes)
                    {
                        newProductsList.Add(CreateProductFromType(productType));
                    }
                }
                else
                {
                    List<ProductType> candidates = new List<ProductType>(ProductTypes);
                    for (; itemsToSelect > 0; --itemsToSelect)
                    {
                        int index = rand.Next(0, candidates.Count);
                        newProductsList.Add(CreateProductFromType(candidates[index]));
                        candidates.RemoveAt(index);
                    }
                }

                return newProductsList;
            }
        }

        #endregion

    }
}
